#include "./handler_task.h"
#include "../driver/nozzle.h"
#include "../driver/cmd_uart.h"
#include "../driver/door.h"
#include "../driver/scan_uart.h"
#include "../cfg/app_info.h"
#include "../service/exec.h"

namespace task {

HandlerTask handlerTask;

using namespace conn;
using namespace driver;
using namespace utils;
using namespace cfg;
using namespace service;

static void on_nozzle_ctrl(const Message &msg) {
    uint16_t mm;
    Error err = msg.parse_req(mm);
    if (err) {
        goto finish;
    }    
    err = nozzle.run(mm);
finish:
    cmdUart.res(msg, err);
}

static void on_door_ctrl(const Message &msg) {
    uint8_t v;
    Error err = msg.parse_req(v);
    if (err) {
        goto finish;
    }
    switch (v) {
        case 0: err = door.open(); break;
        case 1: err = door.close(); break;
        default: err = ec::INVALID; break;
    }
finish:
    cmdUart.res(msg, err);
}

static void on_scan(const Message &msg) {
    ByteView result;
    Error err = scanUart.scan(result);
    cmdUart.res(msg, err, result);
}

static void on_set_param(const Message &msg) {
    uint8_t key;
    uint16_t v;
    Error err = msg.parse_req(key, v);
    if (err) {
        goto finish;
    }
    switch (key) {
        case 0: appInfo->flow_count_1000L = v; break;
        case 1: appInfo->steam_heat_temp = v;  break;
        case 2: appInfo->steam_heat_kpa = v; break;
        case 3: appInfo->steam_heat_timeout = v * 60 * 1000; break;
        case 4: appInfo->water_heat_temp = v; break;
        case 5: appInfo->water_heat_timeout = v * 60 * 1000; break;
        case 6: appInfo->draw_timeout = v * 60 * 1000; break;
        default: err = ec::INVALID; goto finish;
    }
    err = appInfo.save();
finish:
    cmdUart.res(msg, err);
}

void on_draw_water_ctrl(const Message &msg) {
    uint16_t mm;
    uint8_t temp;
    uint16_t ml;
    Error err = msg.parse_req(mm, temp, ml);
    if (err) {
        goto finish;
    }
    err = exec::nozzle_draw_water(mm, temp, ml);
finish:
    cmdUart.res(msg, err);
}

void on_draw_water_ctrl2(const Message &msg) {
    uint16_t ml;
    Error err = msg.parse_req(ml);
    if (err) {
        goto finish;
    }
    err = exec::draw_water(ml);
finish:
    cmdUart.res(msg, err);
}

void HandlerTask::run() {

    for (;;) {
        Message msg = m_mq.take();
        m_task_info.seq = msg.seq();
        m_task_info.cmd = msg.cmd();

        switch (msg.cmd()) {

            case proto::CMD_NOZZLE_CTRL: on_nozzle_ctrl(msg); break;
            case proto::CMD_DOOR_CTRL: on_door_ctrl(msg); break;
            case proto::CMD_SCAN: on_scan(msg); break;
            case proto::CMD_PARAM: on_set_param(msg); break;
            case proto::CMD_DRAW_WATER_CTRL: on_draw_water_ctrl(msg); break;
            case proto::CMD_DRAW_WATER2_CTRL: on_draw_water_ctrl2(msg); break;
        }

        m_task_info.reset();
    }
}

}
